﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Silverlight.Testing;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PlottingBasics.PlotManipulations;
using System.Linq;

namespace t_PlottingBasics
{
    [TestClass]
    public class t_IntegralCalculations
    {
        [TestMethod]
        public void TestGetIntegralCurveSinglePoint()
        {
            Point[] ar = new Point[] { new Point(0.0, 2.0) };
            var result = IntegralCalculations.IntegralCurve(ar);
            Assert.AreEqual(1, result.Count(), "Wrong number of elements back");
            Assert.AreEqual(0.0, result.First().X, "incorrect x value back");
            Assert.AreEqual(1.0, result.First().Y, "incorrect y value came back");
        }

        [TestMethod]
        public void TestGetInegralNullSequence()
        {
            var result = IntegralCalculations.IntegralCurve(new Point[0]);
            Assert.AreEqual(0, result.Count(), "Null sequence is not right");
        }

        [TestMethod]
        public void TestGetIntegralCurveTwoPoints()
        {
            Point[] ar = new Point[] { new Point(0.0, 1.0), new Point(1.0, 2.0) };
            var result = IntegralCalculations.IntegralCurve(ar);
            Assert.AreEqual(2, result.Count(), "Wrong number of elements back");
            Assert.AreEqual(0.0, result.First().X, "incorrect x value back (first)");
            Assert.AreEqual(1.0, result.Last().X, "incorrect x value back (second)");
            Assert.AreEqual(0.0, result.First().Y, "incorrect y value came back (first)");
            Assert.AreEqual(1.0, result.Last().Y, "incorrect y value came back (second)");
        }

        [TestMethod]
        public void TestGetIntegralSequence()
        {
            Point[] ar = new Point[] {
                new Point (0.0, 0.0),
                new Point(1.0, 0.5),
                new Point(2.0, 1.0),
                new Point(3.0, 1.5),
                new Point(4.0, 2.0)
            };
            var result = IntegralCalculations.IntegralCurve(ar).ToArray();
            Assert.AreEqual(ar.Length, result.Length, "Improper size");
            Assert.AreEqual(0.0, result[0].Y, "Shoudl start with zero");
            Assert.AreEqual(0.0, result[1].Y*3.0, "1 is not right");
            Assert.AreEqual(0.5, result[2].Y*3.0, "2 is not right");
            Assert.AreEqual(1.5, result[3].Y*3.0, "3 is not right");
            Assert.AreEqual(3.00, result[4].Y*3.0, "4 is not right");
        }

        [TestMethod]
        public void TestGetIntegralFlatSequence()
        {
            Point[] ar = new Point[] {
                new Point(0.0, 5.0),
                new Point(1.0, 5.0),
                new Point(2.0, 5.0),
                new Point(3.0, 5.0)
            };

            var result = IntegralCalculations.IntegralCurve(ar).ToArray();
            Assert.AreEqual(ar.Length, result.Length, "Improper size");
            for (int i = 0; i < 4; i++)
            {
                Assert.AreEqual(5.0 * i, result[i].Y * 15.0, "Expected item at index " + i + " not found");
            }
        }

        [TestMethod]
        public void TestFlattenCurveLessThanIntegralCutBeyondEnd()
        {
            var ar = new Point[] {
                new Point (0.0, 1.0),
                new Point (1.0, 1.0),
                new Point (2.0, 1.0),
                new Point (3.0, 1.0)
            };

            var result = ar.FlattenCurveLessThanIntegralCut(1.0).ToArray();

            Assert.AreEqual(2, result.Count(), "Wrong number in result sequence");
            Assert.AreEqual(0.0, result[0].Y, "0 is wrong");
            Assert.AreEqual(0.0, result[1].Y, "1 is wrong");
            Assert.AreEqual(0.0, result[0].X, "0.x is wrong");
            Assert.AreEqual(3.0, result[1].X, "1.x is wrong");
        }

        [TestMethod]
        public void TestFlattenCurveLessThanIntegralCutInMiddle()
        {
            var ar = new Point[] {
                new Point (0.0, 1.0),
                new Point (1.0, 1.0),
                new Point (2.0, 1.0),
                new Point (3.0, 1.0)
            };

            var result = ar.FlattenCurveLessThanIntegralCut(0.75).ToArray();

            Assert.AreEqual(4, result.Count(), "Wrong number in result sequence");
            Assert.AreEqual(0.0, result[0].Y, "0 is wrong");
            Assert.AreEqual(0.0, result[1].Y, "1 is wrong");
            Assert.AreEqual(0.0, result[0].X, "0.x is wrong");
            Assert.AreEqual(2.25, result[2].X, "2.x is wrong");
            Assert.AreEqual(1.0, result[2].Y, "2.Y is wrong");
            Assert.AreEqual(3.0, result[3].X, "3.x is wrong");
            Assert.AreEqual(1.0, result[3].Y, "3.y is wrong");
        }

        [TestMethod]
        public void TestFlattenCurveLessThanIntegralCutBeforeStart()
        {
            var ar = new Point[] {
                new Point (0.0, 1.0),
                new Point (1.0, 1.0),
                new Point (2.0, 1.0),
                new Point (3.0, 1.0)
            };

            var result = ar.FlattenCurveLessThanIntegralCut(0).ToArray();

            Assert.AreEqual(0.0, result[0].X, "0.x is wrong");
            Assert.AreEqual(1.0, result[1].X, "1.x is wrong");
            Assert.AreEqual(2.0, result[2].X, "2.x is wrong");
            Assert.AreEqual(3.0, result[3].X, "3.x is wrong");

            Assert.AreEqual(1.0, result[0].Y, "0.y is wrong");
            Assert.AreEqual(1.0, result[1].Y, "1.y is wrong");
            Assert.AreEqual(1.0, result[2].Y, "2.y is wrong");
            Assert.AreEqual(1.0, result[3].Y, "3.y is wrong");
        }

        [TestMethod]
        public void TestFractionProbabilityAfterXBasic()
        {
            var ar = new Point[] {
                new Point (0.0, 1.0),
                new Point (1.0, 1.0),
                new Point (2.0, 1.0),
                new Point (3.0, 1.0),
                new Point (4.0, 1.0)
            };
            var result = ar.FractionProbabilityBeforeX(2.0);
            Assert.AreEqual(0.5, result, "fraction not right");
            Assert.AreEqual(0.25, ar.FractionProbabilityBeforeX(1.0), "1 doesn't work correctly");
            Assert.AreEqual(0.75, ar.FractionProbabilityBeforeX(3.0), "3 doesn't work correctly");
        }

        [TestMethod]
        public void TestFractionOfProbabilityAfterXInFirst()
        {
            var ar = new Point[] {
                new Point (0.0, 1.0),
                new Point (1.0, 1.0),
                new Point (2.0, 1.0),
                new Point (3.0, 1.0),
                new Point (4.0, 1.0)
            };
            var result = ar.FractionProbabilityBeforeX(0.5);
            Assert.AreEqual(0.25 / 2, result, "Initial spot isn't right");
        }

        [TestMethod]
        public void TestFractionProbabilityAfterXAfterEnd()
        {
            var ar = new Point[] {
                new Point (0.0, 1.0),
                new Point (1.0, 1.0),
                new Point (2.0, 1.0),
                new Point (3.0, 1.0),
                new Point (4.0, 1.0)
            };
            var result = ar.FractionProbabilityBeforeX(10.0);
            Assert.AreEqual(1.0, result, "fraction not right");
        }

        [TestMethod]
        public void TestFractionProbabilityAfterXBeforeStart()
        {
            var ar = new Point[] {
                new Point (0.0, 1.0),
                new Point (1.0, 1.0),
                new Point (2.0, 1.0),
                new Point (3.0, 1.0),
                new Point (4.0, 1.0)
            };
            var result = ar.FractionProbabilityBeforeX(-1.0);
            Assert.AreEqual(0.0, result, "fraction not right");
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void TestFractionProbabilityAfterXNullSequence()
        {
            var ar = new Point[0];
            var result = ar.FractionProbabilityBeforeX(1.0);
        }

        [TestMethod]
        public void TestFractionProbabilityAfterXTriangleOnTheWayDown()
        {
            var ar = new Point[] {
                new Point (0.0, 0.0),
                new Point(1.0, 1.0),
                new Point (2.0, 2.0),
                new Point (3.0, 3.0),
                new Point(4.0, 2.0),
                new Point(5.0, 1.0),
                new Point(6.0, 0.0)
            };
            var probLeft = ar.FractionProbabilityBeforeX(4.1);
            var xpos = ar.XPosOfRemainingProbability(probLeft);
            Assert.AreEqual(4.1, xpos, "Not the right spot!");
        }

        [TestMethod]
        public void TestFractionProbabilityAfterXTriangleOnTheWayUp()
        {
            var ar = new Point[] {
                new Point (0.0, 0.0),
                new Point(1.0, 1.0),
                new Point (2.0, 2.0),
                new Point (3.0, 3.0),
                new Point(4.0, 2.0),
                new Point(5.0, 1.0),
                new Point(6.0, 0.0)
            };
            var probLeft = ar.FractionProbabilityBeforeX(2.1);
            var xpos = ar.XPosOfRemainingProbability(probLeft);
            Assert.AreEqual(2.1, xpos, "Not the right spot!");
        }

        [TestMethod]
        public void TestXPosOfRemainingProbabilityBasic()
        {
            var ar = new Point[]
            {
                new Point (0.0, 1.0),
                new Point (1.0, 1.0),
                new Point (2.0, 1.0),
                new Point (3.0, 1.0),
                new Point (4.0, 1.0)
            };

            var result = ar.XPosOfRemainingProbability(0.5);
            Assert.AreEqual(2.0, result, "Didn't get back right position where probability is set!");
        }

        [TestMethod]
        public void TestXPosOfRemainingProbabilityInFirstInterval()
        {
            var ar = new Point[]
            {
                new Point (0.0, 1.0),
                new Point (1.0, 1.0),
                new Point (2.0, 1.0),
                new Point (3.0, 1.0),
                new Point (4.0, 1.0)
            };

            var result = ar.XPosOfRemainingProbability(0.25/2.0);
            Assert.AreEqual(0.5, result, "Didn't get back right position where probability is set!");
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void TestXPosOfRemainingProbabilityBadProbPos()
        {
            var ar = new Point[]
            {
                new Point (0.0, 1.0),
                new Point (1.0, 1.0),
                new Point (2.0, 1.0),
                new Point (3.0, 1.0),
                new Point (4.0, 1.0)
            };

            var result = ar.XPosOfRemainingProbability(1.1);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void TestXPosOfRemainingProbabilityBadProbNeg()
        {
            var ar = new Point[]
            {
                new Point (0.0, 1.0),
                new Point (1.0, 1.0),
                new Point (2.0, 1.0),
                new Point (3.0, 1.0),
                new Point (4.0, 1.0)
            };

            var result = ar.XPosOfRemainingProbability(-0.3);
        }

        [TestMethod]
        [Exclusive]
        public void TestXPosOfRemainingProbabilityBadProbAtStart()
        {
            var ar = new Point[]
            {
                new Point (0.0, 1.0),
                new Point (1.0, 1.0),
                new Point (2.0, 1.0),
                new Point (3.0, 1.0),
                new Point (4.0, 1.0)
            };

            var result = ar.XPosOfRemainingProbability(0.0);
            Assert.AreEqual(0.0, result, "X at start not right");
        }

        [TestMethod]
        [Exclusive]
        public void TestXPosOfRemainingProbabilityBadProbAtEnd()
        {
            var ar = new Point[]
            {
                new Point (0.0, 1.0),
                new Point (1.0, 1.0),
                new Point (2.0, 1.0),
                new Point (3.0, 1.0),
                new Point (4.0, 1.0)
            };

            var result = ar.XPosOfRemainingProbability(1.0);
            Assert.AreEqual(4.0, result, "X at end not right");
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void TestXPosOfRemainingProbabilityNull()
        {
            var ar = new Point[0];
            var result = ar.XPosOfRemainingProbability(1.0);
        }
    }
}